<?php
/******************************************************
	MXML proxy version 3.5 on 8 May 2010
	
	Change history:
	8/05/2010 - KMI - fix file upload
	11/04/2010 - KMI - added stylesheet validation 
	
	Author genericframe ltd
********************************************************/

	header("Content-Type: text/html; charset=utf-8");

	require_once 'HTTP/Request2.php';
    require_once('log4php/Logger.php');
    Logger::configure('log4php.properties');
	Logger::configure('resources/appender_file.properties');
      
  
########## ##########  START GLOBAL config ########## ##########	
define("TRACE", true); // set these to false when production 
define("DUMP_PHPINFO", false); // creates a trace.html including the phpinfo() from the current request

$xmlfile = 'genericframe.xml'; // used by offline mode - no SQL to genericframe DB is called
########## ##########  END GLOBAL config  ########## ##########
$template = '';
$applicationName = '';
$action = '';
$startpage = '';
$traceStr = '';

function strleft($s1, $s2) { 
	return substr($s1, 0, strrpos($s1, $s2)); 
}	
function HandleXmlError($errno, $errstr, $errfile, $errline)
{
   print_r($errstr);
   if ($errno==E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
   {
       throw new Exception($errstr);
   }
   else
       return false;
}
function debug() {
	echo "\nFile:".__FILE__ . "Line:" .__LINE__."";
}	

function templateLookup($doc, $appTemplateLocation, $applicationName) {
	
	$root =& $doc->documentElement;
	$children =& $root->childNodes;
						
	$items = $doc->getElementsByTagName('template');
	foreach ($items as $item) {
		$name = $item->getAttribute( 'name' );										
		if ($name != null || $name != '') {
			$templateContent = file_get_contents("$appTemplateLocation/$name.mxml");
			
			$templateContentdoc = DOMDocument::loadXML($templateContent);
			if ($templateContentdoc == null) {
				// in the case the template has an ERROR and can not be parsed
				echo "*** Template ERROR:$appTemplateLocation/$name.mxml\r\n";
				$error = error_get_last();
				$error= $error['message'];
				print_r($error);
				$chunks = spliti ("\n", $templateContent);
				print_r($chunks);
				$response = $error;
				$counter = 0;
			
				$doc = new DOMDocument("1.0", "UTF-8");
				$root = $doc->createElement('generic');
				$doc->appendChild($root);
				
				$port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]); 
				$path = strleft($_SERVER['REQUEST_URI'], "/");
				$errorUrl = "http://".$_SERVER['HTTP_HOST'].$port.$path."/trace/.trace".$applicationName.".txt"; 

				$format = '<html><body><h1>Template '.$name.'.mxml has XML ERROR:</h1><br /><a href="%s" target="_blank">Trace file</a><br /><h3>Stream:</h3><p>%s</p></body></html>';
				
				$error = sprintf($format, $errorUrl, $response);
				
				$xhtml = $doc->createElement('xhtml', $error);
				$root->appendChild($xhtml);
				return $doc;
			} else {			
				$newelement = $templateContentdoc->documentElement;		
				$item->appendChild($doc->importNode($newelement, true));
			}
		}
	}
	return $doc;
}

function emu_getallheaders() {
	foreach($_SERVER as $h=>$v) {
		if(ereg('HTTP_(.+)',$h,$hp)) {
			$headers[$hp[1]]=$v;
		}
	}
	return $headers;
}

function libxml_display_error($error)
{
    $return = "<br/><h4>";
    switch ($error->level) {
        case LIBXML_ERR_WARNING:
            $return .= "<b>Warning</b>: ";
            break;
        case LIBXML_ERR_ERROR:
            $return .= "<b>Error</b>: ";
            break;
        case LIBXML_ERR_FATAL:
            $return .= "<b>Fatal Error</b>: ";
            break;
    }
    $return .= trim($error->message);
    if ($error->file) {
    	// print_r($error);
        $return .=    " at reponse ";
    }
    $line = $error->line;
    $line += 1;
    $return .= " on line <b> $line </b>\n";
    $return .= "</h4>";

    return $return;
}

function libxml_display_errors() {
    $errors = libxml_get_errors();
    foreach ($errors as $error) {
        print libxml_display_error($error);
    }
    libxml_clear_errors();
}

function _getallheaders() {
   	foreach($_SERVER as $name => $value) {
		if(substr($name, 0, 5) == 'HTTP_') {
           	$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
		} else if(substr($name, 0, 5) == 'CONTE') {
			$headers[$name] = $value;
		}
	}
   	return $headers;
}

	if (!function_exists('getallheaders')) {		
		$headers = _getallheaders();
	} else {
		$headers = getallheaders();
	}
	$map = $_REQUEST;

//	unset($map['PHPSESSID']);	// done on purphose
########## ##########  START Logger  ########## ##########
	$logger = Logger::getRootLogger();		
########## ##########  START THE TRACE  ########## ##########
ob_start();	
########## ##########  WRITE THE HEADERS & REQUEST  ########## ##########
print_r("###### PAGE LIFE CYCLE ##############################
Timestamp: ".date("F j, Y, H:i:s a ")."

 1. REQUEST 
 2. ACTION LOOKUP 
 3. CALLING ACTION 
 4. ACTION RESPONSE 
 5. FINAL RESPONSE\r\n\r\n");
print_r("\r\n\r\n###### 1. REQUEST ##############################\r\n\r\n");
print_r($headers);
########## ##########  START PROCESSING  ########## ##########
	$ctType = '';
	if (isset($headers['Content-Type'])) {
		$ctType = $headers['Content-Type'];
	} else if (isset($headers['Content-type'])) {
		$ctType = $headers['Content-type'];
	} else if (isset($headers['CONTENT_TYPE'])) {
		$ctType = $headers['CONTENT_TYPE'];
	}	

	if ($ctType  == '' || $ctType  == 'application/x-www-form-urlencoded' ) {	
		foreach ( $map as $key => $val) {
			$map[$key] = str_replace("\\", '', $val);
		}

		$map['FormData'] = str_replace("\\", '', $map['FormData']);
		$map['action'] = str_replace("\\", '', $map['action']);
		
		$docinput = new SimpleXMLElement($map['FormData']);
		$template = $docinput->template;
		$applicationName = $docinput->applicationName;
		$action = $docinput->action;
		$startpage = $docinput->startpage;		
	} else { 
		echo '*** multipart/form-data FILE SET';
		$map['FormData'] = str_replace("\\", '', $map['FormData']);		
		foreach ( $map as $key => $val) {
			$map[$key] = str_replace("\\", '', $val);
			echo $key.'\r\n';
		}

		$map['FormData'] = str_replace("\\", '', $map['FormData']);
		$map['action'] = str_replace("\\", '', $map['action']);
					
		$docinput = new SimpleXMLElement($_REQUEST["FormData"]);		
		$applicationName = $docinput->applicationName;
		$action = urldecode($map['action']);
		
		$filename = urldecode($map['file_txt']);
				
		$uploads_dir = $_SERVER['DOCUMENT_ROOT'] .  dirname($_SERVER['PHP_SELF']); // current location of the mxmlproxy
		$tmp_name = $_FILES['Filedata']['tmp_name'];
		if (!file_exists('.uploads')) {
			mkdir('.uploads');
		}
		if (move_uploaded_file($tmp_name, "$uploads_dir/.uploads/$filename")) { // put all uploades into currentlocation/uploads
			echo '***Upload recieved '.$filename."\r\n";
		}
		echo '*** Application:'.$applicationName.' Action:'.$action."\r\n";
		unset($map['Filename']);	// done on purphose
		// unset($map['file_txt']);	// done on purphose
	}

	$OFFLINE = false;	
	if (file_exists($applicationName.".xml")) { 
		$OFFLINE = true;
		$xmlfile = $applicationName.".xml";
	}
	print_r("\r\n###### 2. ACTION LOOKUP ##############################\r\n\r\n");
	
	########## ##########  OFFLINE ONLINE  ########## ##########	
	########## #####  SAME as online just read the XML   ########## ######
	if ($OFFLINE == true) {
		$xmlinfoS = simplexml_load_file($xmlfile);
		/* Relative paths also work... */		
		$path ="//*[applicationName='".$applicationName."']";
		$xpathResult = $xmlinfoS->xpath($path);
		
		echo '*** XPATH '.$path."\r\n";
		print_r($xpathResult[0]);
		$simpleXMLElement = $xpathResult[0];
		
		$appApplicationinstance_id = $simpleXMLElement->id;
		$appStartPageTypeAction = $simpleXMLElement->startPageTypeAction;
		$appStartPage = $simpleXMLElement->startPage;
		$appApplicationUri = $simpleXMLElement->applicationUri;
		$appTemplateLocation = $simpleXMLElement->templateLocation;
		
		if ($startpage != '' && $appStartPageTypeAction == 1) {
			// in these case we have a action as start page
			$action = $appStartPage;
			$startpage = '';
		}
		echo '*** startPage'. $startpage."\r\n";
		
		if ($action != null && trim($action) != '') {
			$taction = str_replace("'", "''", $action); //  convert ' -> '' needed for SQL execute		

			$path ="//*[applicationInsanceId='".$appApplicationinstance_id."']";	
			$xpathActionResult = $xmlinfoS->xpath($path);

			echo "*** Execute Action XPATH :".date("H:i:s   ").$path."\r\n";
			while(list( , $node) = each($xpathActionResult)) {
				if (strcmp($node->actionName,$action) == 0) {			    
					echo "*** Found Action :\r\n";
					print_r($node);
					$template = $node->startPage;
					$actionUri = $node->actionUri;
					
					break;
				}
			}	
			if (!isset($actionUri)) {
				echo "*** Action $action not found look for default action \r\n";
				$xpathActionResult = $xmlinfoS->xpath($path);
				while(list( , $node) = each($xpathActionResult)) {
					if (strcmp($node->defaultaction,"1") == 0) {			    
						echo "*** Found Default Action :\r\n";
						print_r($node);
						$template = $node->startPage;
						$actionUri = $node->actionUri;						
						break;
					}
				}				
			}
			if (!isset($actionUri)) {
				echo "*** For Application $applicationName Could not find an action with name $taction \r\n";
			}
		} else {
			$template = $appStartPage;
		}
	} else {
    	include_once("dbFactory.php");

	    $sql = "select * from applicationinstance where applicationName = '$applicationName'";
		$applicationinstanceResult = &$conn->Execute($sql); 
		if (!$applicationinstanceResult->EOF) {
			$appApplicationinstance_id = $applicationinstanceResult->fields['id'];
			$appStartPageTypeAction = $applicationinstanceResult->fields['startPageTypeAction'];
			$appStartPage = $applicationinstanceResult->fields['startPage'];
			$appApplicationUri = $applicationinstanceResult->fields['applicationUri'];
			$appTemplateLocation = $applicationinstanceResult->fields['templateLocation'];

			if ($startpage != '' && $appStartPageTypeAction == 1) {
				// in these case we have a action as start page
				$action = $appStartPage;
				$startpage = '';
			}
			if ($action != null && $action != '') {
				$taction = str_replace("'", "''", $action); //  convert ' -> '' needed for SQL execute
				
				$sqlaction = "select * from applicationaction where applicationInsanceId = $appApplicationinstance_id and actionName = '$taction'";
				$applicationactionResult = &$conn->Execute($sqlaction); 
				$applicationinstanceResult->Close(); # optional
				
				echo "*** Execute Action SQL :".date("H:i:s   ").$sqlaction."\r\n";
				if (!$applicationactionResult->EOF) {
					$template = $applicationinstanceResult->fields['startPage'];			
					$actionUri = $applicationactionResult->fields['actionUri'];			
				} 
				if (!isset($actionUri)) {
					echo "*** Action $action not found look for default action \r\n";
					$sqlaction = "select * from applicationaction where applicationInsanceId = $appApplicationinstance_id and defaultaction = 1";
					$applicationactionResult = &$conn->Execute($sqlaction); 
					if (!$applicationactionResult->EOF) {
						$template = $applicationinstanceResult->fields['startPage'];			
						$actionUri = $applicationactionResult->fields['actionUri'];			
					} 
					$applicationactionResult = &$conn->Execute($sqlaction); 
				}
				if (!isset($actionUri)) {
					echo "*** For Application $applicationName Could not find an action with name $taction \r\n";
				}				
			} else {
				$template = $appStartPage;
			}			
		}	
		$conn->Close(); # optional
	}
	########## ##########  We now have everything what we need  ########## ##########
	
	print_r("\r\n###### 3. CALLING ACTION #############################\r\n\r\n");
	
	$action = str_replace("\\", '', $action);
	$logger->debug(getenv("REMOTE_ADDR") . " $applicationName $action   " );
	if (true) {		
		
		if ( $startpage != '' ) {		    
			// return the start page 			
			$doc = new DOMDocument();			
			$root = $doc->createElement('generic');
			$doc->appendChild($root);

			// write the templates
			// out.println("<template name='" + template + "'>");
			$child = $doc->createElement('template');
			$root->appendChild($child);
			// create attribute node
			$temp = $doc->createAttribute("name");
			$child->appendChild($temp);

			// create attribute value node
			$tempValue = $doc->createTextNode($template);
			$temp->appendChild($tempValue);			

			// write the data
			$templatedata = $doc->createElement('templatedata');
			$root->appendChild($templatedata);
			
			print_r($template);
			$doc = templateLookup($doc, $appTemplateLocation, $applicationName);
		} else {			
			if (substr($actionUri,0,strlen('file://')) == 'file://') {
				// providerResponse = parser.readFile(applicationaction.getActionUri(), "");					
			} else {
				if (isset($actionUri)) {					
					$url = parse_url($appApplicationUri.$actionUri);					
					$path = (!empty($url['path']) ? $url['path'] : "/").(!empty($url['query']) ? "?".$url['query'] : "");
					do { // do while is required for redirect only
						$calledpath = $path; 
						// call the php
						$response = "";						
						/* $url structure:
							[scheme] => http
							[host] => 127.0.0.1
							[port] => 85
							[path] => /genericframe/xxxx/xxx.php						
						*/
						echo '***Calling:'. $url['scheme'].'://'.$url['host'].($url['port']?":".$url['port']:"").$path."\r\n";
						if (isset($filename)) {
							echo "*** File upload:".$appApplicationUri."\r\n";
							$client = new HTTP_Request2($url['scheme'].'://'.$url['host'].($url['port']?":".$url['port']:"").$path, HTTP_Request2::METHOD_POST);
							// $client->setHeader("Content-Type", "multipart/form-data; charset=utf-8");
							$client->addUpload('Filedata', "$uploads_dir/.uploads/$filename");					
						} else {
							$client = new HTTP_Request2($url['scheme'].'://'.$url['host'].($url['port']?":".$url['port']:"").$path, HTTP_Request2::METHOD_POST);
							// $client->setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); // do not add these line
						}
						echo "***Params\r\n";
						foreach ( $map as $key => $val) {							
							if ($key != 'ci_session') {
								echo $key. "     ".$val."\r\n";
								$client->addPostParameter($key, $val );
							}
						}				
//						$client->addPostParameter('PHPSESSID', strrev($sid)); // we 2nd sid for calling HTTP reverse original $sid is the remote $sid
						try {							
							$request_cookies = $_COOKIE;
							if(is_array($request_cookies)){
								foreach ($_COOKIE as $key => $val) {
									echo $key. "     ".$val."\r\n";
									$client->addCookie($key, $val );
								}
							}
							/* ZANNI (11.02.2010 19:17), set time out to 20 minutes to avoid the XML Error in the client (Flex):
							Error Message at client: No response & Malformed response: while calling http://lab.genericframe.com/mitkop/sdp/php/case_list.php
							Warning:  DOMDocument::loadXML() [<a href='domdocument.loadxml'>domdocument.loadxml</a>]: Start tag expected, '&lt;' not found in Entity, line: 1 in <b>/home/chroot/home/MXMLProxyServer/mxmlproxy.php</b> on line <b>412</b><br />
							*/							
							$client->setConfig(array('timeout' => 1200));//timeout is set to 1200 seconds
							$responseA = $client->send();
							$response = $responseA->getBody();
							//ZANNI - get headers
							$response_cookies = $responseA->getCookies();
							//$response_headers = $responseA->getHeader();//not used at the moment
							$callStatus = $responseA->getStatus();
							$cur_encoding = mb_detect_encoding($response) ; 
						} catch (Exception $e) {
							echo 'Caught exception: ', $e->getMessage(), "\n";
							$calling = 'http://'.$url['host'].$path;
							$response = htmlspecialchars("No response & Malformed response: while calling $calling");
							$cur_encoding = 'UTF-8';
						}						
												
						print_r("\r\n\r\n###### 4. ACTION RESPONSE ##############################\r\n\r\n");		
						echo "***Response encoded:".$cur_encoding.'   '.date("H:i:s   ")."\r\n";
						echo "***Response status:".$callStatus.'   '.date("H:i:s   ").$path."\r\n";
						// echo $response;

						// set the error handling only in case sucessful execute
						if ($callStatus == '200') {
							set_error_handler('HandleXmlError');
						} 
						if ($callStatus == '302') {	
							// handle redirect
							echo $responseA->getReasonPhrase();
							if ($responseA->getHeader( 'location' ) != $path) {
								$path = $responseA->getHeader( 'location' );
							}
							echo '*** REDIRECT new PATH'.$path;
						} 
					} while ($path != $calledpath); // done for redirect handle
					
					try {
						$doc = new DOMDocument('1.0', "utf-8");
						if ('UTF-8' != $cur_encoding) {
							echo "\r\n*** DO UTF8 ENCODE"."***\r\n";
							$status = $doc->loadXML(utf8_encode($response));								
						} else {
							$status = $doc->loadXML($response);		
						}
						// 
						$doc->encoding = /*"iso-8859-15"*/ "utf-8";
					} catch (Exception $e) {
						echo '***Caught exception: '.date("H:i:s   "),  $e->getMessage(), "\n";
						$chunks = spliti ("\n", $response);
						print_r($chunks);
						if (strlen($response) < 5000) {
							$response = $e->getMessage().$response;
						} else {
							$response = $e->getMessage();
						}
					}
				}
				restore_error_handler();							
				// in the case document could not be loaded as XML for what ever reasion , send a error
				if (!isset($actionUri) || $status != 1 || $callStatus == '404') {
					$doc = new DOMDocument();
					$root = $doc->createElement('generic');
					$doc->appendChild($root);
					
					$port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]); 
					$path = strleft($_SERVER['REQUEST_URI'], "/");
					$errorUrl = "http://".$_SERVER['HTTP_HOST'].$port.$path."/trace/.trace".$applicationName.".txt"; 
					if (!isset($actionUri)) {
						$format = '<html><body><h1>Not Defined Action:</h1><h3>Application %s requires action %s which is not defined. Please check whether the action name is correct and is defined in %s.</h3><br /><a href="%s" target="_blank">Trace file</a><br /></body></html>';
						$parm1 = "genericframe Database";
						if ($OFFLINE) {
							$parm1 = $xmlfile;
						} 
						$error = sprintf($format, $applicationName, $action, $parm1, $errorUrl);
					} else {
						$format = '<html><body><h1>XML ERROR:</h1><h3>%s Action %s calling %s</h3><br /><a href="%s" target="_blank">Trace file</a><br /><h3>Stream:</h3><p>%s</p></body></html>';
						$error = sprintf($format, $actionUri, $action, $actionUri, $errorUrl, $response);
					}
					if (strlen($response) > 100) {
						// $response = substr($response, 0 , 100);
					}
					
					$xhtml = $doc->createElement('xhtml', $error);
					$root->appendChild($xhtml);
				}
				
				$doc = templateLookup($doc, $appTemplateLocation, $applicationName);
			}
		} // end case action			
	}	
	print_r("\r\n\r\n###### 5. FINAL RESPONSE ##############################\r\n\r\n");
	print_r($doc->saveXML());
	
	########## ##########  WRITE THE TRACE  ########## ##########
	$my_php = ob_get_contents();
	ob_end_clean();
	if (TRACE) {
		$myFile = "trace".$applicationName.".txt";
		$fh = fopen("trace/.".$myFile, 'w') or die("can't open file");
		fwrite($fh, $my_php);
		fclose($fh);	
	}
	
	########## ##########  WRITE STATISTIC  ########## ##########
	if ($OFFLINE == false) {
		$conn->Connect(SERVER,USER,PASSWORD,DATABASE); //uses constants from settings.php
        $conn->EXECUTE("set names 'utf8'");  
		$ip = getenv("REMOTE_ADDR") ; 
		if (isset($error)) { 
			$sql = "INSERT INTO applicationstatistic (applicationid, user, calling, status, errortext) values (" 
			   .'\''. mysql_real_escape_string($applicationName) . '\','
			   .'\''. $ip .'\','
			   .'\''. mysql_real_escape_string($action).'\','
			   .'0,'
			   .'\''. mysql_real_escape_string($error)."')";
		} else {
			$sql = "INSERT INTO applicationstatistic (applicationid, user, calling) values (" 
			   .'\''. mysql_real_escape_string($applicationName) . '\','
			   .'\''. $ip .'\','
			   .'\''. mysql_real_escape_string($action)."')";
		}
		$ok = $conn->Execute($sql); 
		if (!$ok) {
		}
		$conn->Close(); # optional		
	}
	########## ##########  OUTPUT SEND TO FLEX  ########## ##########
	########## ##########  START THE PHPINFO  ########## ##########
	if (DUMP_PHPINFO) {
		ob_start();	
		phpinfo () ;
		$pinfo = ob_get_contents () ;
		ob_end_clean () ;
		$fh = fopen("trace/trace.html", 'w') or die("can't open file");
		fwrite($fh, $pinfo);
		fclose($fh);		
	}
	########## ##########  END THE PHPINFO  ########## ##########
	
	// $output->encoding='utf-8';
	//ZANNI - set headers
	if(is_array($response_cookies)){
		foreach($response_cookies as $val){
			setcookie($val[name],$val[value]);
		}
	}
	/*
	Validate content only when required
	*/
	ob_start();
	libxml_use_internal_errors(true);
	
	$orgdoc = new DOMDocument();
	$orgdoc->loadXML($doc->saveXML());
	$validateXSD = $docinput->validateresponsestructure;
	
	if ($validateXSD  == "true" && !$orgdoc->schemaValidate("release/1.0/generic.xsd")) {	    
	    libxml_display_errors();
	}
		
	$error = ob_get_contents();
	ob_end_clean();
	
	if (!$error) {
		echo $doc->saveXML();
	} else {
		$format = '<html><body><h1>Invalid Element/Attribute:</h1>%s</body></html>';
		$error = sprintf($format, $error);

		$root = $doc->documentElement;		
		$xhtml = $doc->createElement('xhtml', $error);
		$root->appendChild($xhtml);
								
		echo $doc->saveXML();
	}
?>
